/*
 * SHOPTNT 版权所有。
 * 未经许可，您不得使用此文件。
 * 官方地址：www.shoptnt.cn
 */
package cn.shoptnt.framework.elasticsearch;

import cn.shoptnt.framework.elasticsearch.core.ElasticEnumVersion;
import cn.shoptnt.framework.elasticsearch.core.ElasticSearchResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.searchbox.action.Action;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.*;
import io.searchbox.indices.Analyze;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.IndicesExists;
import io.searchbox.indices.mapping.PutMapping;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Es 操作工具类
 * @author liuyulei
 * @version 1.0
 * @since 7.2.2
 * 2021/1/21  17:36
 */
public class ElasticOperationUtil {

    private final static Logger logger = LoggerFactory.getLogger(ElasticOperationUtil.class);

    /**
     * 创建索引
     * @param jestClient  jest客户端
     * @param indexName   索引名称
     * @return
     */
    public static boolean createIndex(JestClient jestClient,String indexName,Map source){
        // 构建创建信息  索引名称  映射关系
        CreateIndex.Builder builder = new CreateIndex.Builder(indexName);
        JestResult jestResult = null;
        // ES6 使用此方式构建映射
        if (ElasticBuilderUtil.version.startsWith(ElasticEnumVersion.ES6.getVersion())) {
            // 先创建索引
            jestResult = execute(jestClient,builder.build());
            // 再推送映射
            putMapping(jestClient,indexName,source);
        } else if (ElasticBuilderUtil.version.startsWith(ElasticEnumVersion.ES7.getVersion())){
            // ES7 使用此方式构建映射
            builder.mappings(source);
            // 获取返回结果
            jestResult = execute(jestClient,builder.build());
        } else {
            // 其他版本暂未兼容  TODO
        }

        return getResult(jestResult);
    }

    /**
     * 创建映射
     * @param jestClient
     * @param indexName
     * @param source
     * @return
     */
    private static boolean putMapping(JestClient jestClient,String indexName,Map source) {
        PutMapping putMapping = new PutMapping.Builder(indexName,EsSettings.TYPE_NAME,source).build();
        // 获取返回结果
        JestResult jestResult = execute(jestClient,putMapping);
        return getResult(jestResult);
    }


    /**
     * 删除索引
     * @param jestClient  jest客户端
     * @param indexName   索引名称
     * @return
     */
    public static  boolean deleteIndex(JestClient jestClient,String indexName) {
        DeleteIndex.Builder deleteIndex = new DeleteIndex.Builder(indexName);
        JestResult jestResult = execute(jestClient,deleteIndex.build());
        return getResult(jestResult);
    }

    /**
     * 搜索数据
     * @param jestClient  jest客户端
     * @param indexName   索引名称
     * @param query       查询条件
     * @return
     */
    public static  ElasticSearchResult search(JestClient jestClient,String indexName,  String query) {
        logger.debug("ES 查询条件>>>>>:{}",query);
        Search search = new Search.Builder(query)
                .addIndex(indexName)
                .addType(EsSettings.TYPE_NAME)
                .build();

        SearchResult searchResult = execute(jestClient,search);
        logger.debug("ES 查询结果>>>>>{}",searchResult.toString());
        // 如果失败则返回
        if (!searchResult.isSucceeded()) {
            return null;
        }
        return new ElasticSearchResult(searchResult);
    }


    /**
     * 插入数据
     * @param jestClient  jest客户端
     * @param indexName   索引名称
     * @param obj         数据对象
     * @return
     */
    public static  boolean insert(JestClient jestClient,String indexName,  Object obj) {
        //构建插入
        Index index = new Index.Builder(obj).index(indexName).type(EsSettings.TYPE_NAME).build();
        //执行并返回结果
        JestResult jestResult = execute(jestClient,index);
        return getResult(jestResult);
    }

    /**
     * 批量插入
     * @param jestClient  jest客户端
     * @param indexName   索引名称
     * @param objs        数据对象列表
     * @return
     */
    public static  boolean insertBatch(JestClient jestClient,String indexName, List<Object> objs) {
        // 构建批量插入
        Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexName).defaultType(EsSettings.TYPE_NAME);
        // 循环数据列表 构建数据
        for (Object obj : objs) {
            Index index = new Index.Builder(obj).build();
            bulk.addAction(index);
        }
        // 执行并返回结果
        BulkResult bulkRequest = execute(jestClient,bulk.build());
        return getResult(bulkRequest);
    }


    /**
     * 获取版本号
     * @param jestClient   jest客户端
     * @return
     */
    public static  String version(JestClient jestClient) {
        Ping getSettings = new Ping.Builder().build();
        JestResult jr =execute(jestClient,getSettings);
        return jr == null ? "" :  jr.getJsonObject().get("version").getAsJsonObject().get("number").getAsString();
    }

    /**
     * 判断索引是否存在
     * @param jestClient  jest客户端
     * @param indexName   索引名称
     * @return
     */
    public static  boolean indicesExists(JestClient jestClient,String indexName) {
        IndicesExists indicesExists = new IndicesExists.Builder(indexName).build();
        JestResult jestResult = execute(jestClient,indicesExists);
        return getResult(jestResult);
    }
    /**
     * 根据条件删除，满足条件的进行删除
     * @param jestClient   jest客户端
     * @param indexName    索引名称
     * @param query        查询条件
     * @return
     */
    public static boolean deleteByQuery(JestClient jestClient,String indexName,String query) {
        logger.debug("ES 删除条件>>>>>:{}",query);
        DeleteByQuery delete = new DeleteByQuery.Builder(query).addIndex(indexName).addType(EsSettings.TYPE_NAME).build();
        JestResult jestResult = execute(jestClient,delete);
        logger.debug("ES 删除结果>>>>>{}",jestResult.toString());
        return getResult(jestResult);
    }

    /**
     * 分词
     * @param jestClient   jest客户端
     * @param txt          待分词数据
     * @return
     */
    public static  List<String> analyzer(JestClient jestClient,String txt) {
        List<String> result = new ArrayList<>();
        Analyze analyze = new Analyze.Builder().text(txt).analyzer("ik_smart").build();
        JestResult jestResult = execute(jestClient,analyze);
        jestResult.getJsonObject().get("tokens").getAsJsonArray().forEach( token -> {
            result.add(token.getAsJsonObject().get("token").getAsString());
        });
        return result;
    }


    /**
     * 获取 jest client 执行结果
     * @param jestResult   jest客户端
     * @return
     */
    private static boolean getResult(JestResult jestResult) {
        return jestResult != null && jestResult.isSucceeded();
    }

    /**
     * Jest client  执行
     * @param clientRequest
     * @return
     */
    private static  <T extends JestResult> T execute(JestClient jestClient,Action<T> clientRequest){
        T jr;
        try {
            jr = jestClient.execute(clientRequest);
        } catch (IOException e) {
            logger.error("JestClient Error :{}",e.getMessage(),e);
            return null;
        }
        // 如果返回结果不为空，且为失败，且不是判断索引存在的  输出异常信息
        if (jr != null && !jr.isSucceeded() &&  ! (clientRequest instanceof IndicesExists)) {
            logger.error("JestClient execute  Error :{}",jr.getErrorMessage());
        }

        return jr;
    }
}
